﻿namespace Community.CsharpSqlite.Entity
{
    /*
    ** CAPI3REF: Application Defined Page Cache.
    ** KEYWORDS: {page cache}
    ** EXPERIMENTAL
    **
    ** ^(The [ConfigHelper.Sqlite3Config]([ConfigOption.SQLITE_CONFIG_PCACHE], ...) interface can
    ** register an alternative page cache implementation by passing in an 
    ** instance of the sqlite3_pcache_methods structure.)^ The majority of the 
    ** heap memory used by SQLite is used by the page cache to cache data read 
    ** from, or ready to be written to, the database file. By implementing a 
    ** custom page cache using this API, an application can control more 
    ** precisely the amount of memory consumed by SQLite, the way in which 
    ** that memory is allocated and released, and the policies used to 
    ** determine exactly which parts of a database file are cached and for 
    ** how long.
    **
    ** ^(The contents of the sqlite3_pcache_methods structure are copied to an
    ** internal buffer by SQLite within the call to [ConfigHelper.Sqlite3Config].  Hence
    ** the application may discard the parameter after the call to
    ** [ConfigHelper.Sqlite3Config()] returns.)^
    **
    ** ^The xInit() method is called once for each call to [sqlite3_initialize()]
    ** (usually only once during the lifetime of the process). ^(The xInit()
    ** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^
    ** ^The xInit() method can set up up global structures and/or any mutexes
    ** required by the custom page cache implementation. 
    **
    ** ^The xShutdown() method is called from within [sqlite3_shutdown()], 
    ** if the application invokes this API. It can be used to clean up 
    ** any outstanding resources before process shutdown, if required.
    **
    ** ^SQLite holds a [MutexType.SQLITE_MUTEX_RECURSIVE] mutex when it invokes
    ** the xInit method, so the xInit method need not be threadsafe.  ^The
    ** xShutdown method is only called from [sqlite3_shutdown()] so it does
    ** not need to be threadsafe either.  All other methods must be threadsafe
    ** in multithreaded applications.
    **
    ** ^SQLite will never invoke xInit() more than once without an intervening
    ** call to xShutdown().
    **
    ** ^The xCreate() method is used to construct a new cache instance.  SQLite
    ** will typically create one cache instance for each open database file,
    ** though this is not guaranteed. ^The
    ** first parameter, szPage, is the size in bytes of the pages that must
    ** be allocated by the cache.  ^szPage will not be a power of two.  ^szPage
    ** will the page size of the database file that is to be cached plus an
    ** increment (here called "R") of about 100 or 200.  ^SQLite will use the
    ** extra R bytes on each page to store metadata about the underlying
    ** database page on disk.  The value of R depends
    ** on the SQLite version, the target platform, and how SQLite was compiled.
    ** ^R is constant for a particular build of SQLite.  ^The second argument to
    ** xCreate(), bPurgeable, is true if the cache being created will
    ** be used to cache database pages of a file stored on disk, or
    ** false if it is used for an in-memory database. ^The cache implementation
    ** does not have to do anything special based with the value of bPurgeable;
    ** it is purely advisory.  ^On a cache where bPurgeable is false, SQLite will
    ** never invoke xUnpin() except to deliberately delete a page.
    ** ^In other words, a cache created with bPurgeable set to false will
    ** never contain any unpinned pages.
    **
    ** ^(The xCachesize() method may be called at any time by SQLite to set the
    ** suggested maximum cache-size (number of pages stored by) the cache
    ** instance passed as the first argument. This is the value configured using
    ** the SQLite "[PRAGMA cache_size]" command.)^  ^As with the bPurgeable
    ** parameter, the implementation is not required to do anything with this
    ** value; it is advisory only.
    **
    ** ^The xPagecount() method should return the number of pages currently
    ** stored in the cache.
    ** 
    ** ^The xFetch() method is used to fetch a page and return a pointer to it. 
    ** ^A 'page', in this context, is a buffer of szPage bytes aligned at an
    ** 8-byte boundary. ^The page to be fetched is determined by the key. ^The
    ** mimimum key value is 1. After it has been retrieved using xFetch, the page 
    ** is considered to be "pinned".
    **
    ** ^If the requested page is already in the page cache, then the page cache
    ** implementation must return a pointer to the page buffer with its content
    ** intact.  ^(If the requested page is not already in the cache, then the
    ** behavior of the cache implementation is determined by the value of the
    ** createFlag parameter passed to xFetch, according to the following table:
    **
    ** <table border=1 width=85% align=center>
    ** <tr><th> createFlag <th> Behaviour when page is not already in cache
    ** <tr><td> 0 <td> Do not allocate a new page.  Return NULL.
    ** <tr><td> 1 <td> Allocate a new page if it easy and convenient to do so.
    **                 Otherwise return NULL.
    ** <tr><td> 2 <td> Make every effort to allocate a new page.  Only return
    **                 NULL if allocating a new page is effectively impossible.
    ** </table>)^
    **
    ** SQLite will normally invoke xFetch() with a createFlag of 0 or 1.  If
    ** a call to xFetch() with createFlag==1 returns NULL, then SQLite will
    ** attempt to unpin one or more cache pages by spilling the content of
    ** pinned pages to disk and synching the operating system disk cache. After
    ** attempting to unpin pages, the xFetch() method will be invoked again with
    ** a createFlag of 2.
    **
    ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page
    ** as its second argument. ^(If the third parameter, discard, is non-zero,
    ** then the page should be evicted from the cache. In this case SQLite 
    ** assumes that the next time the page is retrieved from the cache using
    ** the xFetch() method, it will be zeroed.)^ ^If the discard parameter is
    ** zero, then the page is considered to be unpinned. ^The cache implementation
    ** may choose to evict unpinned pages at any time.
    **
    ** ^(The cache is not required to perform any reference counting. A single 
    ** call to xUnpin() unpins the page regardless of the number of prior calls 
    ** to xFetch().)^
    **
    ** ^The xRekey() method is used to change the key value associated with the
    ** page passed as the second argument from oldKey to newKey. ^If the cache
    ** previously contains an entry associated with newKey, it should be
    ** discarded. ^Any prior cache entry associated with newKey is guaranteed not
    ** to be pinned.
    **
    ** ^When SQLite calls the xTruncate() method, the cache must discard all
    ** existing cache entries with page numbers (keys) greater than or equal
    ** to the value of the iLimit parameter passed to xTruncate(). ^If any
    ** of these pages are pinned, they are implicitly unpinned, meaning that
    ** they can be safely discarded.
    **
    ** ^The xDestroy() method is used to delete a cache allocated by xCreate().
    ** All resources associated with the specified cache should be freed. ^After
    ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*]
    ** handle invalid, and will not use it with any other sqlite3_pcache_methods
    ** functions.
    */
    //typedef struct sqlite3_pcache_methods sqlite3_pcache_methods;
    //struct sqlite3_pcache_methods {
    //  void *pArg;
    //  int (*xInit)(void*);
    //  void (*xShutdown)(void*);
    //  sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable);
    //  void (*xCachesize)(sqlite3_pcache*, int nCachesize);
    //  int (*xPagecount)(sqlite3_pcache*);
    //  void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
    //  void (*xUnpin)(sqlite3_pcache*, void*, int discard);
    //  void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey);
    //  void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
    //  void (*xDestroy)(sqlite3_pcache*);
    //};
    public class sqlite3_pcache_methods
    {
        public object pArg;
        public dxPC_Cachesize xCachesize; //public void (*xCachesize)(sqlite3_pcache*, int nCachesize);
        public dxPC_Create xCreate; //public sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable);
        public dxPC_Destroy xDestroy; //public void (*xDestroy)(sqlite3_pcache*);
        public dxPC_Fetch xFetch; //public void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
        public dxPC_Init xInit; //int (*xInit)(void*);
        public dxPC_Pagecount xPagecount; //public int (*xPagecount)(sqlite3_pcache*);
        public dxPC_Rekey xRekey; //public void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey);
        public dxPC_Shutdown xShutdown; //public void (*xShutdown)(void*);
        public dxPC_Truncate xTruncate; //public void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
        public dxPC_Unpin xUnpin; //public void (*xUnpin)(sqlite3_pcache*, void*, int discard);

        public sqlite3_pcache_methods()
        {
        }

        public sqlite3_pcache_methods(object pArg, dxPC_Init xInit, dxPC_Shutdown xShutdown, dxPC_Create xCreate,
                                      dxPC_Cachesize xCachesize, dxPC_Pagecount xPagecount, dxPC_Fetch xFetch,
                                      dxPC_Unpin xUnpin, dxPC_Rekey xRekey, dxPC_Truncate xTruncate,
                                      dxPC_Destroy xDestroy)
        {
            this.pArg = pArg;
            this.xInit = xInit;
            this.xShutdown = xShutdown;
            this.xCreate = xCreate;
            this.xCachesize = xCachesize;
            this.xPagecount = xPagecount;
            this.xFetch = xFetch;
            this.xUnpin = xUnpin;
            this.xRekey = xRekey;
            this.xTruncate = xTruncate;
            this.xDestroy = xDestroy;
        }
    };
}